#define _CRT_SECURE_NO_WARNINGS 1
一：对 << 和 >> 的重载实现

友元函数可访问类的私有和保护成员，但不是类的成员函数
友元函数不能用const修饰
友元函数可以在类定义的任何地方声明，不受类访问限定符限制
一个函数可以是多个类的友元函数
友元函数的调用与普通函数的调用原理相同

cout能自动识别类型 其实是一大堆的函数重载，遇见什么类型就调用此类型的函数（内置类型之所以能直接支持你用，是因为 ostream 已经帮你写好了。）

cout 其实是一个全局类型的对象，这个对象的类型是 ostream ，也就是说ostream是一个类 cout是其实例化出的对象
------------------------------------------------ -
<< 是一个双操作数的操作符 左操作数为cout 右操作数为后面的变量 例如 cout << a

开始重载：

类中的声明：
void operator<<(ostream & out);

类外的定义：

void Date::operator<<(ostream& out)
{
	out << _year << "/" << _month << "/" << _day << endl;   //变成了几个内置类型的打印
}

解释：
如前文所说，cout 其实是一个全局类型的对象，这个对象的类型是 ostream ，也就是说ostream是一个类 cout是其实例化出的对象
cout 传给 ostream& out 接收, cout是一个系统已经写好的对象，它的类是 ostream，然后这里是用对象引用来接受一个对象

此时cout << d1是不行的，但是d1 << cout 是可以的
因为系统规定双操作数的运算符 第一个参数是左操作数 第二为右  所以我们平时写的cout << d1 cout就是第一个参数 d1是第二个参数 当我们像上面那样写 第一个参数是this


所以我们写的
d1.operator<<(&d1, cout);
这里是写出来方便理解，但是不能写出& d1

d1.operator<<(cout); 是对的


所以我们将其写在类外，变成了全局函数才可以

void operator<<(ostream& out, const Date& d);
//而第一个参数不加const是因为 其会改变 记住就行


void operator<<(ostream& out, const Date& d)
{
	out << d._year << "/" << d._month << "/" << d._day << endl;
}

这样main中还是不可以 cout << d1;
因为全局函数没有权限访问私有成员变量，所以我们就用友元

友元函数可以直接访问类的私有成员，它是定义在类外部的普通函数。

它不属于任何类，但需要在类的内部进行声明，声明时要加 friend 关键字

class Date {
public:
	friend void operator<<(ostream& out, const Date& d);  // 友元的声明
	//...

private:
	int _year;
	int _month;
	int _day;
};

------------------------------------------------ -

新的问题：

无法 cout << d1 << d2；
因为真正的cout可以连续的打印


连续插入 d1 和 d2 实际上就是两次函数的调用，这里先执行的是 cout << d1

因为调用函数后返回值是 void，void会作为这里的左操作数

所以当然不支持连续输出了，我们可以改一下，

我们把返回值改为 ostream 就行，把 out 返回回去吗，也就是达到了cout << d1 这一步所需要的打印的效果 还让下一步变成了cout << d2
------------------------------------------------ -

代码：
Date.h

class Date
{
public:
	// ...

	friend ostream& operator<<(ostream& out, const Date& d);    // 友元的声明



private:
	int _year;
	int _month;
	int _day;
};
----------------------------------
💬 Date.cpp

#include "Date.h"

ostream& operator<<(ostream& out, const Date& d) {
	out << d._year << "/" << d._month << "/" << d._day << endl;

	return out;
}
------------------------------------
💬 test.cpp

int main(void)
{
	Date d1(2022, 3, 20);
	Date d2(2021, 5, 1);
	cout << d1 << d2;

	return 0;
}
————————————————------------------------------------------
cin 该对象的类型是 istream

流提取因为要把输入的东西写到对象里去，会改变，所以这里当然不能加 const 。

friend istream& operator>>(istream& in, Date& d);

istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}

——------------------------------------------------------友友元类：

class Date;   // 前置声明

class Time {
	friend class Date; // 声明日期类为时间类的友元类，则在日期类中就直接访问Time类中的私有成员变量

	这里 Date 是 Time 的友元，我们在日期类里就可以访问时间类的私有成员了。

		但是时间类里不能访问日期类，因为这是 "单向好友" ，

		如果想在时间类里访问日期类，我们可以在日期类里声明：

		class Date {
		friend class Time;
		// ...
	}

	这样，它们之间就是 "双向好友" 了 —— 互相成为对方的友元

		--------------------------------------------------------
		想对this进行const修饰，因为this是隐藏的，所以要const写到函数的末尾！

		这个时候 const就是const修饰的了（const Date * this = &d）

		成员函数定义的原则：
		①：能对this const一定要const修饰，这样const和非const能用
		②：需要修改成员变量的成员函数，不能const，此时const对象不能用，非const才能用
		③：全局函数不能加const，没有this，何来const修饰this？

		----------------------------------------------------------
		C++默认成员函数的取地址重载：

		这两个默认成员函数一般不用重新定义 ，编译器默认会生成

		class Date
	{
	public:
		Date* operator&()
		{
			return this;
		}
		const Date* operator&()const
		{
			return this;
		}
	private:
		int _year; // 年
		int _month; // 月
		int _day; // 日
	};

	这两个运算符一般不需要重载，使用编译器生成的默认取地址的重载即可，只有特殊情况，才需要重载，比如想让别人获取到指定的内容！
		——-------------------------------------------------- -

		初始化列表：
		博客讲解




